iT邦幫忙

2022 iThome 鐵人賽

DAY 25
0
自我挑戰組

Spring In Action系列 第 25

Send request as a client in reactive programming

  • 分享至 

  • xImage
  •  

這段介紹如何在reactive的Spring中發送request。

在SpringMVC中我們會使用RestTemplate,而在WebFlux中我們會使用WebClient來做到一樣的事情:

Mono<Ingredient> ingredient = WebClient.create()
    .get()
    .uri("http://localhost:8081/ingredients/{id}", ingredientId)
    .retrieve()
    .bodyToMono(Ingredient.class);
ingredient.subscribe(i -> { ... });

若想要加base URI到webclient中,可以建置一個Bean來做到:

@Bean
public WebClient webClient() {
  return WebClient.create("http://localhost:8081");
}
@Autowired
WebClient webClient;
public Mono<Ingredient> getIngredientById(String ingredientId) {
  Mono<Ingredient> ingredient = webClient
    .get()
    .uri("/ingredients/{id}", ingredientId)
    .retrieve()
    .bodyToMono(Ingredient.class);
  ingredient.subscribe(i -> { ... });
}

設置timeout可串接在stream中:

Flux<Ingredient> ingredients = webclient
    .get()
    .uri("/ingredients")
    .retrieve()
    .bodyToFlux(Ingredient.class);
ingredients
  .timeout(Duration.ofSeconds(1))
  .subscribe(
      i -> { ... },
      e -> {
        // handle timeout error
      });

夾帶資料發送post:

Mono<Ingredient> ingredientMono = Mono.just(
    new Ingredient("Valyrian", "Valyrian steel", Ingredient.Type.BLADE));
Mono<Ingredient> result = webClient
  .post()
  .uri("/ingredients")
  .body(ingredientMono, Ingredient.class)
  .retrieve()
  .bodyToMono(Ingredient.class);
result.subscribe(i -> { ... });

可使用bodyValue直接把object放進request中:

Ingredient ingredient = ...;
Mono<Ingredient> result = webClient
  .post()
  .uri("/ingredients")
  .bodyValue(ingredient)
  .retrieve()
  .bodyToMono(Ingredient.class);
result.subscribe(i -> { ... });

處理不同的http status,可在接回來的Mono或Flux接上subscribe時處理:

ingredientMono.subscribe(
    ingredient -> {
      // handle the ingredient data
      ...
    },
    error-> {
      // deal with the error
      ...
    });

或者在webclient的stream中使用onStatus處理:

Mono<Ingredient> ingredientMono = webClient
    .get()
    .uri("http://localhost:8081/ingredients/{id}", ingredientId)
    .retrieve()
    .onStatus(HttpStatus::is4xxClientError,
            response -> Mono.just(new UnknownIngredientException()))
    .bodyToMono(Ingredient.class);

以上範例都是透過retrieve()來處理response,背地裡是將ResponseSpec這個物件作處理後拿出其內容,不過如果我們需要header之類的response資訊時,就不適合直接使用retrieve()了,要用exchangeToMono或exchangeToFlux來拿到完整的ResponseSpec物件:

Mono<Ingredient> ingredientMono = webClient
    .get()
    .uri("http://localhost:8081/ingredients/{id}", ingredientId)
    .exchangeToMono(cr -> {
      if (cr.headers().header("X_UNAVAILABLE").contains("true")) {
        return Mono.empty();
      }
      return Mono.just(cr);
    })
    .flatMap(cr -> cr.bodyToMono(Ingredient.class));

上一篇
Reactive persistence
下一篇
RSocket
系列文
Spring In Action30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言